<?php

/*
 * CopyRight  : (C)2012-2099 HaoTeam Inc.
 * Document   : TencentFaceService.php
 * Created on : 2023-2-21 15:22:17
 * Author     : Tiger <1192851302@qq.com>
 * Description: This is NOT a freeware, use is subject to license terms.
 *              这即使是一个免费软件,使用时也请遵守许可证条款,得到当时人书面许可.
 *              未经书面许可,不得翻版,翻版必究;版权归属 HaoTeam Inc;
 */

namespace haoteam\service;

use haoteam\service\HttpService;
use think\facade\Cache;

/**
 * 腾讯人脸验证
 * Class TencentFaceService
 * Tiger <1192851302@qq.com> 2023-2-21 15:22:17
 */
class TencentFaceService {

    protected $config = [];
    protected $access_token = '';
    protected $user_id = '';
    protected $tickets = '';
    protected $api = 'https://miniprogram-kyc.tencentcloudapi.com/api';
    protected $nonce = '';
    protected $licence = 'RE0PqiZ1uU2+2DHc/vqkat007aFICcSE/a2j09Y/S0HsDAJcBly2q49OR1dL503FgvV1winwdDTu/0DearqKPiKU2g23aJqc7LzX01N1ncHRoAgpjtI3O+kifKO8kGIyvhnruXatD6wOYq8oxwHJXllrn0rmnNHUmG35aLGXOXevSJ3KUYXYBnNcOswPI2GL8Hd0rTovivjuE1pzHuHFt4OX1xzcp4UWF/B7wmxGEMXmdNmxOzwtuRm6WJrEBvWnrUj4M+Ujq30RWjTQYoSGzVSwz4nrrluqtuS9zo+NzER7zGyU7ts9o+cXzMu6BF8XePzL3SSnr50RTF6GyEhdpw==';

    /**
     * 快速实例化模型
     * @author Tiger <1192851302@qq.com>
     * @param bool $singleton 是否单例
     * @return static
     */
    public static function instance($singleton = true) {
        $name = static::class;
        if (isset($GLOBALS['model'][$name]) and is_object($GLOBALS['model'][$name]) and $singleton) {
            $that = $GLOBALS['model'][$name];
        } else {
            $GLOBALS['model'][$name] = new static();
            $that = $GLOBALS['model'][$name];
        }
        $that->config = config('third.tencent.face');
        return $that;
    }

    public function token() {
        $access_token = Cache::get('tencent_face_access_token');
        if ($access_token) {
            $this->access_token = $access_token;
            return $this;
        }

        $return = $this->request($this->api . '/oauth2/access_token', 'get', array_merge($this->config, [
            'grant_type' => 'client_credential'
        ]));
        $this->access_token = $return['access_token'];
        Cache::set('tencent_face_access_token', $return['access_token'], 1200);
        return $this;
    }

    /**
     * 
     * @param type $user_id
     * @return $this
     */
    public function ticket($user_id, $type = 'SIGN') {
        $this->user_id = $type == 'SIGN' ? "userId{$user_id}" : $user_id;
        $return = $this->request($this->api . '/oauth2/api_ticket', 'get', array_merge($this->config, [
            'access_token' => $this->access_token,
            'type' => $type,
            'user_id' => $this->user_id
        ]));
        $this->tickets = $return['tickets'][0]['value'];
        return $this;
    }

    /**
     * 
     * @return $this
     */
    public function faceid($orderNo, $name, $idNo) {
        $this->nonce = getRandom();
        $this->orderNo = $orderNo;
        $result = $this->request($this->api . '/server/getfaceid?orderNo=' . $orderNo, 'json', [
            'webankAppId' => $this->config['app_id'],
            'orderNo' => $this->orderNo,
            'name' => $name,
            'idNo' => $idNo,
            'userId' => $this->user_id,
            'version' => $this->config['version'],
            'sign' => $this->sign(),
            'nonce' => $this->nonce
        ]);

        return [
            'faces' => $result['result'],
            'userId' => $this->user_id,
            'nonce' => $this->nonce,
            'sign' => $this->token()->ticket($this->user_id, 'NONCE')->sign(),
            'appId' => $this->config['app_id'],
            'orderNo' => $this->orderNo,
            'apiVersion' => $this->config['version'],
            'licence' => $this->licence
        ];
    }

    /**
     * 
     * @author Tiger <1192851302@qq.com>
     * @param type $url
     * @param type $method
     * @param type $data
     * @return type
     * @throws \think\Exception
     */
    public function request($url, $method, $data) {
        try {
            $output = HttpService::instance()->{$method}($url, $data);
        } catch (\Exception $exc) {
            throw new \think\Exception($exc->getMessage());
        }

        if ($output['code'] == 0) {
            return $output;
        }
        throw new \think\Exception($output['msg']);
    }

    /**
     * 签名
     * @return type
     */
    public function sign() {
        $arr = array_values([
            'wbappid' => $this->config['app_id'],
            'userId' => $this->user_id,
            'version' => $this->config['version'],
            'ticket' => $this->tickets,
            'nonce' => $this->nonce
        ]);

        \think\facade\Log::debug('排序前 | ' . json_encode($arr, JSON_UNESCAPED_UNICODE));
        asort($arr, SORT_STRING);
        \think\facade\Log::debug('排序后 | ' . json_encode($arr, JSON_UNESCAPED_UNICODE));
        $str = implode('', $arr);
        \think\facade\Log::debug('加密前 | ' . $str);
        return strtoupper(sha1($str));
    }
}
